package task.timer;

import com.qax.task.timer.HashedWheelTimer;
import com.qax.task.timer.NamedThreadFactory;
import com.qax.task.timer.Timer;
import com.qax.task.timer.TimerTask;
import org.junit.Assert;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.results.BenchmarkResult;
import org.openjdk.jmh.results.IterationResult;
import org.openjdk.jmh.results.RunResult;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.io.PrintStream;
import java.util.Collection;
import java.util.concurrent.TimeUnit;

@State(Scope.Thread)
@BenchmarkMode(Mode.Throughput)
@Warmup(iterations = 3)
@Measurement(iterations = 10, time = 3)
@OutputTimeUnit(TimeUnit.SECONDS)
public class hashedwheeltimerbenchmark {

    Timer timer = new HashedWheelTimer(
            new NamedThreadFactory("future-timeout", true));

    @Param({"1","2"})
    private int  index ;

//    @Benchmark
    public void testNoOpTimerWheelTimeForBenchmarkTestResult() {
        timer.newTimeout(createNoOpTimerTask(),index,TimeUnit.SECONDS);
    }

    /**
     * testIncForNumberWheelTimeForBenchmarkTestResult        1  thrpt    5  1294685.064 ± 317710.582  ops/s
     * testIncForNumberWheelTimeForBenchmarkTestResult        2  thrpt    5  1807357.459 ± 168407.901  ops/s
     *
     * <BR>该方法十次秒级吞吐量均值在>140W<BR/>
     */
    @Benchmark
    public void testIncForNumberWheelTimeForBenchmarkTestResult() {
        timer.newTimeout(createIncForNumberTimerTask(),index,TimeUnit.SECONDS);
    }

    private static TimerTask createNoOpTimerTask() {
        return timeout -> {
        };
    }

    private static TimerTask createIncForNumberTimerTask() {
        return timeout -> {
            int i  ;
            for(i = 0 ; i<10000000;i++){
                i--;
            }
            i ++;
        };
    }

    /**
     * avg:
     *
     * Benchmark                                        (index)  Mode  Cnt    Score     Error  Units
     * testIncForNumberWheelTimeForBenchmarkTestResult        1  avgt    5  791.445 ± 360.743  ns/op
     * testIncForNumberWheelTimeForBenchmarkTestResult        2  avgt    5  715.130 ± 287.256  ns/op
     * testIncForNumberWheelTimeForBenchmarkTestResult        3  avgt    5  735.581 ± 535.227  ns/op
     * testIncForNumberWheelTimeForBenchmarkTestResult        4  avgt    5  851.462 ± 543.648  ns/op
     * testIncForNumberWheelTimeForBenchmarkTestResult        5  avgt    5  808.389 ± 195.904  ns/op
     *
     * ops/s:
     *
     *
     *
     * Benchmark                                        (index)   Mode  Cnt        Score         Error  Units
     * testIncForNumberWheelTimeForBenchmarkTestResult        1  thrpt    5  1620567.606 ± 1230027.734  ops/s
     * testIncForNumberWheelTimeForBenchmarkTestResult        2  thrpt    5  1538831.982 ±  569832.403  ops/s
     * testIncForNumberWheelTimeForBenchmarkTestResult        3  thrpt    5  1243398.652 ±  723169.676  ops/s
     * testIncForNumberWheelTimeForBenchmarkTestResult        4  thrpt    5   857179.385 ± 1014228.122  ops/s
     * testIncForNumberWheelTimeForBenchmarkTestResult        5  thrpt    5  1373268.444 ±  571271.708  ops/s
     * @param args
     * @throws Exception
     */
    public static void main(final String[] args) throws Exception {
        final Options opt = new OptionsBuilder()
                .include(hashedwheeltimerbenchmark.class.getSimpleName())
                 .jvmArgsAppend("-XX:+UnlockDiagnosticVMOptions")
//                 "-XX:+TraceClassLoading",
//                 "-XX:+LogCompilation",
//                 "-XX:+PrintAssembly")
                .threads(1)
                .warmupIterations(1)
                .measurementIterations(5)
                .forks(1)
                .build();
        Collection<RunResult> run = new Runner(opt).run();
        PrintStream out = System.out;
        out.println("Param [] count is  =\t " + run.size());
        run.forEach(e ->{
            BenchmarkResult aggregatedResult = e.getAggregatedResult();
            Collection<IterationResult> iterationResults = aggregatedResult.getIterationResults();
            out.println("iterator count is =\t " + iterationResults.size());
            iterationResults.forEach(e3->{
                Assert.assertEquals("ops/s",e3.getPrimaryResult().getScoreUnit());
                Assert.assertTrue("Mean were  did't  < 1000000 for tps",
                        Double.valueOf(e3.getPrimaryResult().getStatistics().getMean())
                                .compareTo(Double.valueOf(1000000.0D)) == 1);

                Assert.assertEquals(e3.getPrimaryResult().getStatistics().getMean(),e3.getPrimaryResult().getScore(),10);
                Assert.assertEquals(1,e3.getPrimaryResult().getSampleCount());
                Assert.assertEquals(1,e3.getPrimaryResult().getStatistics().getN());
            });
            e.getBenchmarkResults().forEach(e2 ->{
                out.println("label=\t="+e2.getPrimaryResult().getLabel());
                out.println("ScoreUnit=\t="+e2.getPrimaryResult().getScoreUnit());
                out.println("getStatistics.mean=\t="+e2.getPrimaryResult().getStatistics().getMean());
                out.println("getScore=\t="+e2.getPrimaryResult().getScore());
                out.println("sampleCount=\t="+e2.getPrimaryResult().getSampleCount());
                out.println("ScoreConfidence=\t="+e2.getPrimaryResult().getScoreConfidence());
                out.println("the number of samples in this statistics=\t="+e2.getPrimaryResult().getStatistics().getN());
                out.println("Percentile=\t="+e2.getPrimaryResult().getStatistics().getPercentile(5));

            });
        });
        out.println(run);
    }
}
